// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

part of dart.core;

/**
 * 表示一个时间点，例如：July 20, 1969, 8:18pm GMT。
 *
 * 通过构造函数或解析格式化的字符串创建DateTime对象，
 * 并且符合ISO 8601标准的子集。
 * 请注意，小时是24小时制，范围在0-23之间。
 * 例如：
 *
 *     DateTime now = new DateTime.now();
 *     DateTime berlinWallFell = new DateTime(1989, 11, 9);
 *     DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");  // 8:18pm
 *
 * DateTime对象创建之后，将是固定不变的，无论UTC时区还是当前计算机的本地时区。
 *
 * 一旦被创建，DateTime对象的值和时区都不能被修改。
 *
 * 你可以使用属性来获取DateTime对象的各自单位：
 *
 *     assert(berlinWallFell.month == 11);
 *     assert(moonLanding.hour == 20);
 *
 * 为了便利性和可读性，DateTime类提供有每月和星期对应名称的常量。
 * 例如，[AUGUST]（八月）和[FRIDAY]（周五）。
 * 你可以使用这些常量来提高代码的可读性：
 *
 *     DateTime berlinWallFell = new DateTime(1989, DateTime.NOVEMBER, 9);
 *     assert(berlinWallFell.weekday == DateTime.THURSDAY);
 *
 * 号数和月份从1开始递增，星期也是从[MONDAY]（周一）开始。
 * 也就是说，常量[JANUARY]和[MONDAY]的值都是1。
 *
 * ## UTC和本地时间
 *
 * DateTime对象默认使用的是本地时区，除非显示地指定UTC时区。
 *
 *     DateTime dDay = new DateTime.utc(1944, 6, 6);
 *
 * [isUtc]可以判断DateTime对象是否基于UTC。
 * [toLocal]和[toUtc]方法可以得到等效的另一个时区的日期/时间值。
 * 使用DateTime对象的[timeZoneName]属性，可得到时区的简称。
 * 查看UTC和对象时区之间的时差，可调用[timeZoneOffset]。
 *
 * ## 比较DateTime对象
 *
 * DateTime包含有一些实用的方法用于比较对象，
 * 如：[isAfter]、[isBefore]和[isAtSameMomentAs]。
 *
 *     assert(berlinWallFell.isAfter(moonLanding) == true);
 *     assert(berlinWallFell.isBefore(moonLanding) == false);
 *
 * ## 使用DateTime和Duration
 *
 * [add]和[subtract]方法可通过[Duration]对象创建另一个新的DateTime。
 * 例如，查找今天过后60天的日期，写作：
 *
 *     DateTime today = new DateTime.now();
 *     DateTime sixtyDaysFromNow = today.add(new Duration(days: 60));
 *
 * 获取两个DateTime对象之间的时间差，使用[difference]方法，将返回一个[Duration]对象。
 *
 *     Duration difference = berlinWallFell.difference(moonLanding)
 *     assert(difference.inDays == 7416);
 *
 * 对于不同时区的两个日期的时间差，两个时间点之间仅仅只相差的数纳秒。
 * 它并不需要考虑[日历日](http://baike.baidu.com/view/701112.htm)。这也就意味着，
 * 在本地时间，如果白天在两个时间点之间保留修改的话,
 * 当日零点到次日零点之间的时间差可能小于24小时。
 * 如果上面的时间差使用澳大利亚的本地时间进行计算，时间差是7415天23小时，
 * `inDays`的返回值只有7415天。
 *
 * TODO 待确定完善 class DateTime
 *
 *     翻译上面这段的时候，没有直译，原文很难懂。然后我理解的大概意思是：
 *
 *     国际协调时间（UTC）以原子时秒长为基础，准确度每日数纳秒。如果过去很长的时间，如上面的7416天，
 *     误差会很明显，然后在某一时刻，取余后天数可能会比实际小1天。
 *
 *     下面是原文，如果不对的地方请指正：
 *
 *     The difference between two dates in different time zones is just
 *     the number of nanoseconds between the two points in time.
 *     It doesn't take calendar days into account.
 *     That means that the difference between two midnights in local time
 *     may be less than 24 hours times the number of days between them,
 *     if there is a daylight saving change in between.
 *     If the difference above is calculated using Australian local time,
 *     the difference is 7415 days and 23 hours,
 *     which is only 7415 whole days as reported by inDays.
 *
 * ## 其他资源
 *
 * [Duration]表示一个时间跨度。
 * [Stopwatch]用于测量时间间隔。
 *
 * DateTime类并不提供国际化。如果要使代码国际化，可使用
 * [intl](http://pub.dartlang.org/packages/intl)包。
 *
 */
class DateTime implements Comparable<DateTime> {
  // 星期常量，[weekday]属性getter方法的返回值：
  static const int MONDAY = 1;
  static const int TUESDAY = 2;
  static const int WEDNESDAY = 3;
  static const int THURSDAY = 4;
  static const int FRIDAY = 5;
  static const int SATURDAY = 6;
  static const int SUNDAY = 7;
  static const int DAYS_PER_WEEK = 7;

  // 月份常量，[month]属性getter方法的返回值：
  static const int JANUARY = 1;
  static const int FEBRUARY = 2;
  static const int MARCH = 3;
  static const int APRIL = 4;
  static const int MAY = 5;
  static const int JUNE = 6;
  static const int JULY = 7;
  static const int AUGUST = 8;
  static const int SEPTEMBER = 9;
  static const int OCTOBER = 10;
  static const int NOVEMBER = 11;
  static const int DECEMBER = 12;
  static const int MONTHS_PER_YEAR = 12;

  /**
   * DateTime的值。
   *
   * 该字段的内容依赖于实现。在JavaScript中等于[millisecondsSinceEpoch]。
   * 在VM中等于[microsecondsSinceEpoch]。
   */
  final int _value;

  /**
   * 如果[DateTime]设置成UTC时间，则为True。
   *
   *     DateTime dDay = new DateTime.utc(1944, 6, 6);
   *     assert(dDay.isUtc);
   *
   */
  final bool isUtc;

  /**
   * 构造一个指定为本地时区的[DateTime]。
   *
   * 例如，创建一个新的DateTime对象表示April 29, 2014, 6:04am：
   *
   *     DateTime annularEclipse = new DateTime(2014, DateTime.APRIL, 29, 6, 4);
   */
  DateTime(int year,
           [int month = 1,
            int day = 1,
            int hour = 0,
            int minute = 0,
            int second = 0,
            int millisecond = 0,
            int microsecond = 0])
      : this._internal(
            year, month, day, hour, minute, second, millisecond, microsecond,
            false);

  /**
   * 构造一个指定为UTC时区的[DateTime]。
   *
   *     DateTime dDay = new DateTime.utc(1944, DateTime.JUNE, 6);
   */
  DateTime.utc(int year,
               [int month = 1,
                int day = 1,
                int hour = 0,
                int minute = 0,
                int second = 0,
                int millisecond = 0,
                int microsecond = 0])
    : this._internal(
          year, month, day, hour, minute, second, millisecond, microsecond,
          true);

  /**
   * 在本地时区，通过当前日期和时间构造一个[DateTime]实例。
   *
   *     DateTime thisInstant = new DateTime.now();
   *
   */
  DateTime.now() : this._now();

  /**
   * 基于格式化字符串[formattedString]构建一个新的[DateTime]实例。
   *
   * 如果输入的字符串无法解析，将抛出[FormatException]类型的异常。
   *
   * 函数解析一个被RFC 3339认可的ISO 8601的子集。
   *
   * 当前接受的输入为：
   *
   * * 日期：一个有正负号之分的4-6位数的年份，2位数的月份，2位数的号数，
   *   年、月、日相互间可选`-`进行分割。
   *   例如："19700101"，"-0004-12-24"，"81030-04-01"。
   * * 时间部分为可选项，从日期处以`T`或一个空格分开。
   *   对于时间部分，包括2位数的小时，然后2位数的分钟值可选，然后2位数的秒钟值可选，
   *   然后'.'加1-6位数的秒数可选。分和秒可以用':'分隔。
   *   例如："12"，"12:30:24.124"，"123010.50"。
   * * 时区偏移量为可选项，可能用空格与之前的部分分隔开。时区是'z'或'Z'，
   *   或者是一个有正负之分的2位数的小时部分，和可选的2位数的分钟部分。
   *   符号必须是"+"或"-"，并且不能省略。分钟和小时可能用':'分隔。
   *   例如："Z"，"-10"，"01:30"，"1130"。
   *
   * 这包括[toString]和[toIso8601String]两个输出，将被解析回`DateTime`对象，
   * 并和原始一样，表示相同的时间。
   *
   * 结果始终是本地时间和UTC的其中一个。
   * 如果时区偏移量不同于指定的UTC，则会转换成与UTC等效的时间。
   *
   * 接受的字符串例子：
   *
   * * `"2012-02-27 13:27:00"`
   * * `"2012-02-27 13:27:00.123456z"`
   * * `"20120227 13:27:00"`
   * * `"20120227T132700"`
   * * `"20120227"`
   * * `"+20120227"`
   * * `"2012-02-27T14Z"`
   * * `"2012-02-27T14+00:00"`
   * * `"-123450101 00:00:00 Z"`：年份为-12345
   * * `"2002-02-27T14:00:00-0500"`: 与`"2002-02-27T19:00:00Z"`相同
   */
  // TODO(lrn): restrict incorrect values like  2003-02-29T50:70:80.
  // Or not, that may be a breaking change.
  static DateTime parse(String formattedString) {
    /*
     * date ::= yeardate time_opt timezone_opt
     * yeardate ::= year colon_opt month colon_opt day
     * year ::= sign_opt digit{4,6}
     * colon_opt :: <empty> | ':'
     * sign ::= '+' | '-'
     * sign_opt ::=  <empty> | sign
     * month ::= digit{2}
     * day ::= digit{2}
     * time_opt ::= <empty> | (' ' | 'T') hour minutes_opt
     * minutes_opt ::= <empty> | colon_opt digit{2} seconds_opt
     * seconds_opt ::= <empty> | colon_opt digit{2} millis_opt
     * micros_opt ::= <empty> | '.' digit{1,6}
     * timezone_opt ::= <empty> | space_opt timezone
     * space_opt :: ' ' | <empty>
     * timezone ::= 'z' | 'Z' | sign digit{2} timezonemins_opt
     * timezonemins_opt ::= <empty> | colon_opt digit{2}
     */
    final RegExp re = new RegExp(
        r'^([+-]?\d{4,6})-?(\d\d)-?(\d\d)'  // Day part.
        r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d{1,6}))?)?)?' // Time part.
        r'( ?[zZ]| ?([-+])(\d\d)(?::?(\d\d))?)?)?$'); // Timezone part.

    Match match = re.firstMatch(formattedString);
    if (match != null) {
      int parseIntOrZero(String matched) {
        if (matched == null) return 0;
        return int.parse(matched);
      }

      // Parses fractional second digits of '.(\d{1,6})' into the combined
      // microseconds.
      int parseMilliAndMicroseconds(String matched) {
        if (matched == null) return 0;
        int length = matched.length;
        assert(length >= 1);
        assert(length <= 6);

        int result = 0;
        for (int i = 0; i < 6; i++) {
          result *= 10;
          if (i < matched.length) {
            result += matched.codeUnitAt(i) ^ 0x30;
          }
        }
        return result;
      }

      int years = int.parse(match[1]);
      int month = int.parse(match[2]);
      int day = int.parse(match[3]);
      int hour = parseIntOrZero(match[4]);
      int minute = parseIntOrZero(match[5]);
      int second = parseIntOrZero(match[6]);
      bool addOneMillisecond = false;
      int milliAndMicroseconds = parseMilliAndMicroseconds(match[7]);
      int millisecond =
          milliAndMicroseconds ~/ Duration.MICROSECONDS_PER_MILLISECOND;
      int microsecond =
          milliAndMicroseconds.remainder(Duration.MICROSECONDS_PER_MILLISECOND);
      bool isUtc = false;
      if (match[8] != null) {  // timezone part
        isUtc = true;
        if (match[9] != null) {
          // timezone other than 'Z' and 'z'.
          int sign = (match[9] == '-') ? -1 : 1;
          int hourDifference = int.parse(match[10]);
          int minuteDifference = parseIntOrZero(match[11]);
          minuteDifference += 60 * hourDifference;
          minute -= sign * minuteDifference;
        }
      }
      int value = _brokenDownDateToValue(
          years, month, day, hour, minute, second, millisecond, microsecond,
          isUtc);
      if (value == null) {
        throw new FormatException("Time out of range", formattedString);
      }
      return new DateTime._withValue(value, isUtc: isUtc);
    } else {
      throw new FormatException("Invalid date format", formattedString);
    }
  }

  static const int _MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000;

  /**
   * 用指定的毫秒[millisecondsSinceEpoch]构建一个新的[DateTime]实例。
   *
   * 如果[isUtc]是false，那么日期为本地时区。
   *
   * 在指定的时区（本地或UTC）中，构建的[DateTime]表示
   * 1970-01-01T00:00:00Z + [millisecondsSinceEpoch] ms。
   */
  external DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
                                              {bool isUtc: false});

  /**
   * 用指定的微秒[microsecondsSinceEpoch]构建一个新的[DateTime]实例。
   *
   * 如果[isUtc]是false，那么日期为本地时区。
   *
   * 在指定的时区（本地或UTC）中，构建的[DateTime]表示
   * 1970-01-01T00:00:00Z + [microsecondsSinceEpoch] us。
   */
  external DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
                                               {bool isUtc: false});

  /**
   * 用指定的值构建一个新的[DateTime]实例。
   *
   * 如果[isUtc]为false，那么日期为本地时区。
   */
  DateTime._withValue(this._value, {this.isUtc}) {
    if (millisecondsSinceEpoch.abs() > _MAX_MILLISECONDS_SINCE_EPOCH ||
        (millisecondsSinceEpoch.abs() == _MAX_MILLISECONDS_SINCE_EPOCH &&
         microsecond != 0)) {
      throw new ArgumentError(millisecondsSinceEpoch);
    }
    if (isUtc == null) throw new ArgumentError(isUtc);
  }

  /**
   * 返回true，如果[other]与[DateTime]是同一时刻，并且在相同时区(UTC或本地)。
   *
   *     DateTime dDayUtc   = new DateTime.utc(1944, DateTime.JUNE, 6);
   *     DateTime dDayLocal = new DateTime(1944, DateTime.JUNE, 6);
   *
   *     assert(dDayUtc.isAtSameMomentAs(dDayLocal) == false);
   *
   * 参见 [isAtSameMomentAs]，调整时区之后的比较。
   */
  bool operator ==(other) {
    if (!(other is DateTime)) return false;
    return (_value == other._value && isUtc == other.isUtc);
  }

  /**
   * 返回true，如果[this]在[other]之前出现。
   *
   * 比较与是否是UTC或本地时区无关。
   *
   *     DateTime berlinWallFell = new DateTime(1989, 11, 9);
   *     DateTime moonLanding    = DateTime.parse("1969-07-20 20:18:00");
   *
   *     assert(berlinWallFell.isBefore(moonLanding) == false);
   *
   */
  bool isBefore(DateTime other) {
    return _value < other._value;
  }

  /**
   * 返回true，如果[this]在[other]之后出现。
   *
   * 比较与是否是UTC或本地时区无关。
   *
   *     DateTime berlinWallFell = new DateTime(1989, 11, 9);
   *     DateTime moonLanding    = DateTime.parse("1969-07-20 20:18:00");
   *
   *     assert(berlinWallFell.isAfter(moonLanding) == true);
   *
   */
  bool isAfter(DateTime other) {
    return _value > other._value;
  }

  /**
   * 返回true，如果[this]与[other]在同一时刻出现。
   *
   * 比较与是否是UTC或本地时区无关。
   *
   *     DateTime berlinWallFell = new DateTime(1989, 11, 9);
   *     DateTime moonLanding    = DateTime.parse("1969-07-20 20:18:00");
   *
   *     assert(berlinWallFell.isAtSameMomentAs(moonLanding) == false);
   */
  bool isAtSameMomentAs(DateTime other) {
    return _value == other._value;
  }

  /**
   * 比较此DateTime对象与[other]，
   * 返回0，如果值相等。
   *
   * 如果此DateTime比[other]小（早），则函数返回一个负整数。
   * 或者返回一个正整数，如果更大（后）。
   */
  int compareTo(DateTime other) => _value.compareTo(other._value);

  int get hashCode => (_value ^ (_value >> 30)) & 0x3FFFFFFF;

  /**
   * 返回此DateTime在本地时区的值。
   *
   * 返回[this]，如果它已经是本地时区的值。否则，方法等价于：
   *
   *     new DateTime.fromMicrosecondsSinceEpoch(microsecondsSinceEpoch,
   *                                             isUtc: false)
   */
  DateTime toLocal() {
    if (isUtc) {
      return new DateTime._withValue(_value, isUtc: false);
    }
    return this;
  }

  /**
   * 返回此DateTime在UTC时区的值。
   *
   * 返回[this]，如果它已经是UTC时区的值。否则，方法等价于：
   *
   *     new DateTime.fromMicrosecondsSinceEpoch(microsecondsSinceEpoch,
   *                                             isUtc: true)
   */
  DateTime toUtc() {
    if (isUtc) return this;
    return new DateTime._withValue(_value, isUtc: true);
  }

  static String _fourDigits(int n) {
    int absN = n.abs();
    String sign = n < 0 ? "-" : "";
    if (absN >= 1000) return "$n";
    if (absN >= 100) return "${sign}0$absN";
    if (absN >= 10) return "${sign}00$absN";
    return "${sign}000$absN";
  }

  static String _sixDigits(int n) {
    assert(n < -9999 || n > 9999);
    int absN = n.abs();
    String sign = n < 0 ? "-" : "+";
    if (absN >= 100000) return "$sign$absN";
    return "${sign}0$absN";
  }

  static String _threeDigits(int n) {
    if (n >= 100) return "${n}";
    if (n >= 10) return "0${n}";
    return "00${n}";
  }

  static String _twoDigits(int n) {
    if (n >= 10) return "${n}";
    return "0${n}";
  }

  /**
   * 返回一个对于此实例人们可读的字符串。
   *
   * 返回的字符串是针对此实例的时区构建的。
   * `toString()`方法提供了一个简单的、格式化的字符串。
   * 它不支持国际化的字符串。
   * 可以使用Pub共享包中的[intl](http://pub.dartlang.org/packages/intl)包。
   */
  String toString() {
    String y = _fourDigits(year);
    String m = _twoDigits(month);
    String d = _twoDigits(day);
    String h = _twoDigits(hour);
    String min = _twoDigits(minute);
    String sec = _twoDigits(second);
    String ms = _threeDigits(millisecond);
    String us = microsecond == 0 ? "" : _threeDigits(microsecond);
    if (isUtc) {
      return "$y-$m-$d $h:$min:$sec.$ms${us}Z";
    } else {
      return "$y-$m-$d $h:$min:$sec.$ms$us";
    }
  }

  /**
   * 返回一个按国际标准ISO-8601、全精度扩展格式表示的字符串。
   *
   * 对于UTC时间，格式为`yyyy-MM-ddTHH:mm:ss.mmmuuuZ`。
   * 对于本地/非UTC时间，格式为`yyyy-MM-ddTHH:mm:ss.mmmuuu`（结尾没有"Z"）：
   *
   * * `yyyy`可能是负数，用4位数表示年份，
   *   年份的范围是-9999至9999，或者是有符号的6位数
   * * `MM`是月份，范围是01至12
   * * `dd`是月份中的天数，范围是01至31
   * * `HH`是小时数，范围是00至23
   * * `mm`是分钟数，范围是00至59
   * * `ss`是秒数，范围是00至59（无闰秒）
   * * `mmm`是毫秒，范围是000至999
   * * `uuu`是微秒，范围是001至999。如果[microsecond]等于0，那么这部分省略
   *
   * 使用[parse]，可以将结果字符串可以被解析回DateTime。
   */
  String toIso8601String() {
    String y = (year >= -9999 && year <= 9999) ? _fourDigits(year)
                                               : _sixDigits(year);
    String m = _twoDigits(month);
    String d = _twoDigits(day);
    String h = _twoDigits(hour);
    String min = _twoDigits(minute);
    String sec = _twoDigits(second);
    String ms = _threeDigits(millisecond);
    String us = microsecond == 0 ? "" : _threeDigits(microsecond);
    if (isUtc) {
      return "$y-$m-${d}T$h:$min:$sec.$ms${us}Z";
    } else {
      return "$y-$m-${d}T$h:$min:$sec.$ms$us";
    }
  }

  /**
   * 用[this]加上[duration]，返回一个新的[DateTime]实例。
   *
   *     DateTime today = new DateTime.now();
   *     DateTime sixtyDaysFromNow = today.add(new Duration(days: 60));
   */
  external DateTime add(Duration duration);

  /**
   * 用[this]减去[duration]，返回一个新的[DateTime]实例。
   *
   *     DateTime today = new DateTime.now();
   *     DateTime sixtyDaysAgo = today.subtract(new Duration(days: 30));
   *
   * 注意，对于上面的代码，实际减去的时间是 30 * 24 * 60 * 60 秒。
   * 并且，如果保留白天的时间修改，结果`DateTime`可能并不会在`today`的同一时刻，
   * 实际上也可能不在日历上的前30天。在使用当地时间的时候一定要注意。
   *
   * TODO 待确定完善 DateTime.subtract
   *
   *     附上原文，不对的地方请指正：
   *
   *     Notice that duration being subtracted is actually 30 * 24 * 60 * 60 seconds
   *     and if that crosses a daylight saving time change, the resulting `DateTime`
   *     won't have the same time of day as `today`, and may not actually hit the
   *     calendar date 30 days earlier. Be careful when working with dates in local
   *     time.
   */
  external DateTime subtract(Duration duration);

  /**
   * 计算[this]和[other]的时间差，返回一个[Duration]。
   *
   *     DateTime berlinWallFell = new DateTime.utc(1989, DateTime.NOVEMBER, 9);
   *     DateTime dDay = new DateTime.utc(1944, DateTime.JUNE, 6);
   *
   *     Duration difference = berlinWallFell.difference(dDay);
   *     assert(difference.inDays == 16592);
   *
   * 时间差用秒和秒的小数部分作单位。在上面的代码中，是从开始日期的零点开始计算。
   * 如果上面的日期使用的是本地时间，而不是UTC，由于白天保留的时间差，
   * 两个日期零点之间的时间差可能并不是24小时的倍数。
   *
   * TODO 待确定完善 Duration.difference
   *
   *     The difference is measured in seconds and fractions of seconds.
   *     The difference above counts the number of fractional seconds
   *     between midnight at the beginning of those dates.
   *     If the dates above had been in local time, not UTC,
   *     then the difference between two midnights may not be a multiple of 24 hours
   *     due to daylight saving differences.
   *
   * 例如，在澳大利亚，如果类似的代码使用本地时间，而不是UTC：
   *
   *     DateTime berlinWallFell = new DateTime(1989, DateTime.NOVEMBER, 9);
   *     DateTime dDay = new DateTime(1944, DateTime.JUNE, 6);
   *     Duration difference = berlinWallFell.difference(dDay);
   *     assert(difference.inDays == 16592);
   *
   * 会失败，因为实际上时间差是16591天23小时。[Duration.inDays]仅返回天数。
   */
  external Duration difference(DateTime other);

  external DateTime._internal(int year,
                              int month,
                              int day,
                              int hour,
                              int minute,
                              int second,
                              int millisecond,
                              int microsecond,
                              bool isUtc);

  external DateTime._now();

  /// Returns the time as value (millisecond or microsecond since epoch), or
  /// null if the values are out of range.
  external static int _brokenDownDateToValue(
      int year, int month, int day, int hour, int minute, int second,
      int millisecond, int microsecond, bool isUtc);

  /**
   * 从[Unix epoch](http://baike.baidu.com/view/1908183.htm)
   * `1970-01-01T00:00:00Z (UTC) `开始经过的毫秒数。
   *
   * 该值与时区无关。
   *
   * 这个值最大是
   * 8,640,000,000,000,000ms (100,000,000 days)。
   * 也就是说：`millisecondsSinceEpoch.abs() <= 8640000000000000`.
   */
  external int get millisecondsSinceEpoch;

  /**
   * 从[Unix epoch](http://baike.baidu.com/view/1908183.htm)
   * `1970-01-01T00:00:00Z (UTC) `开始经过的微秒数。
   *
   * 该值与时区无关。
   *
   * 这个值最大是
   * 8,640,000,000,000,000,000us (100,000,000 days)。
   * 也就是说：`microsecondsSinceEpoch.abs() <= 8640000000000000000`.
   *
   * Note that this value does not fit into 53 bits (the size of a IEEE double).
   * A JavaScript number is not able to hold this value.
   */
  external int get microsecondsSinceEpoch;

  /**
   * 由平台提供的时区名称。
   *
   * 在类Unix系统中，这可能是简写。
   * 在Windows系统中，这可能是全称。如，"Pacific Standard Time"。
   */
  external String get timeZoneName;

  /**
   * 时区偏移量，即本地时间和UTC之间的时间差。
   *
   *
   * 对于UTC，时区的东边是正值。
   *
   * 注意，JavaScript、Python和C返回的是UTC和本地时间的差数。
   * Java、C#和Ruby返回的是本地时间和UTC的差数。
   */
  external Duration get timeZoneOffset;

  /**
   * 年。
   *
   *     DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
   *     assert(moonLanding.year == 1969);
   */
  external int get year;

  /**
   * 月份 [1..12]。
   *
   *     DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
   *     assert(moonLanding.month == 7);
   *     assert(moonLanding.month == DateTime.JULY);
   */
  external int get month;

  /**
   * 月份中的天数 [1..31]。
   *
   *     DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
   *     assert(moonLanding.day == 20);
   */
  external int get day;

  /**
   * 小时，使用24小时制 [0..23]。
   *
   *     DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
   *     assert(moonLanding.hour == 20);
   */
  external int get hour;

  /**
   * 分 [0...59]。
   *
   *     DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
   *     assert(moonLanding.minute == 18);
   */
  external int get minute;

  /**
   * 秒 [0...59]。
   *
   *     DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
   *     assert(moonLanding.second == 0);
   */
  external int get second;

  /**
   * 毫秒 [0...999]。
   *
   *     DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
   *     assert(moonLanding.millisecond == 0);
   */
  external int get millisecond;

  /**
   * 微秒 [0...999]。
   *
   *     DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
   *     assert(moonLanding.microsecond == 0);
   */
  external int get microsecond;

  /**
   * 一周中的哪一天，值为[MONDAY]..[SUNDAY]。
   *
   * 按ISO 8601标准，一周从星期一开始，对应的值为1。
   *
   *     DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
   *     assert(moonLanding.weekday == 7);
   *     assert(moonLanding.weekday == DateTime.SUNDAY);
   *
   */
  external int get weekday;
}
